/*

*/

#pragma once

#include "../Common/Net.hpp"
#include "../Common/Message.hpp"
#include <set>

namespace RpcModule
{
    namespace ServerModule
    {
        // 对服务提供者进行的管理
        class ProviderManager
        {
        public:
            using ptr = std::shared_ptr<ProviderManager>;
            // 服务提供者：谁能提供哪些服务
            struct Provider
            {
                using ptr = std::shared_ptr<Provider>;
                std::mutex mutex;
                BaseConnection::ptr conn;
                Address host; // pair<string, int> <ip, 端口号>
                std::vector<std::string> methods;
                Provider(const BaseConnection::ptr &c, const Address &h)
                    : conn(c), host(h) {}
                void AppendMethod(const std::string &method)
                {
                    std::unique_lock<std::mutex> lock(mutex);
                    methods.emplace_back(method);
                }
            };
            // 服务端新增服务时，只需要在服务端对应的provider->method.push_back()即可
            void AddProvider(const BaseConnection::ptr &conn, const Address &host, const std::string &method)
            {
                Provider::ptr provider;
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    // 1. 服务端新增服务，先找到服务端对应的服务提供者
                    auto it = _conns.find(conn);
                    // 2. 维护_conns -- 如果没有providers，创建。有，获取
                    if (it == _conns.end())
                    {
                        LOGDEBUG("服务中心新增服务%s提供者", method.c_str());
                        provider = std::make_shared<Provider>(conn, host);
                        _conns.insert(std::make_pair(conn, provider));
                    }
                    else
                    {
                        LOGDEBUG("服务中心获取服务%s提供者", method.c_str());
                        provider = it->second;
                    }
                    // 3. 维护_providers -- 将provider
                    auto &providers = _providers[method];
                    providers.insert(provider);
                }
                // 4. 服务提供者新增method服务
                provider->AppendMethod(method);
            }
            // 用于服务下线的同时 -- 当一个服务下线时，找到对应的服务提供者，就知道哪些服务要下线了
            Provider::ptr GetProvider(const BaseConnection::ptr &conn)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _conns.find(conn);
                if (it == _conns.end())
                    return Provider::ptr();
                return it->second;
            }
            // 当一个服务提供者断开连接时，删除它的相关信息
            void DeleteProvider(const BaseConnection::ptr &conn)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _conns.find(conn);
                if (it == _conns.end())
                    return;
                // 1. 删除provider，首先要从_providers中删除provider
                // 因为这个提供者已经不能提供特定服务了
                for (auto &method : it->second->methods)
                {
                    auto &providers = _providers[method];
                    providers.erase(it->second);
                }
                // 2. 删除_conns中的provider
                // 因为一个连接删除了特定的provider
                _conns.erase(it);
            }
            std::vector<Address> GetMethodHosts(const std::string &string)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _providers.find(string);
                if (it == _providers.end())
                    return std::vector<Address>();
                std::vector<Address> address;
                for (auto &provider : it->second)
                {
                    address.push_back(provider->host);
                }
                return address;
            }

        private:
            std::mutex _mutex;
            // 什么服务可以被哪些提供者提供 -- Add服务可以被多个提供者提供
            std::unordered_map<std::string, std::set<Provider::ptr>> _providers;
            // 什么连接有哪些提供者 -- 9090端口的提供者能够同时提供Add和Translate两个服务
            std::unordered_map<BaseConnection::ptr, Provider::ptr> _conns;
        };

        // 对服务发现者进行管理
        class DiscoverManager
        {
        public:
            using ptr = std::shared_ptr<DiscoverManager>;
            // 服务发现者，谁发现过什么服务
            struct Discoverer
            {
                using ptr = std::shared_ptr<Discoverer>;
                std::mutex mutex;
                BaseConnection::ptr conn;         // 发现者关联的客户端连接
                std::vector<std::string> methods; // 发现过的服务名称
                Discoverer(const BaseConnection::ptr &c) : conn(c) {}
                void AppendMethod(const std::string &method)
                {
                    std::unique_lock<std::mutex> lock(mutex);
                    methods.push_back(method);
                }
            };
            // 服务端进行服务发现时，第一次发现，就要新增发现者，并且记录发现了什么服务
            Discoverer::ptr AddDiscoverer(const BaseConnection::ptr &conn, const std::string &method)
            {
                // 1. 先找到服务端的服务发现者，如果没有就构造，并插入_conns中
                Discoverer::ptr discoverer;
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    auto it = _conns.find(conn);
                    if (it == _conns.end())
                    {
                        discoverer = std::make_shared<Discoverer>(conn);
                        _conns.insert(std::make_pair(conn, discoverer));
                    }
                    else
                        discoverer = it->second;
                    // 2. 维护_providers
                    // 一个方法被一个新的_providers发现
                    auto &discoverers = _discoverers[method];
                    discoverers.insert(discoverer);
                }
                // 3. 维护discoverer->methods
                discoverer->AppendMethod(method);
                return discoverer;
            }
            // 客户端断开连接时，需要删除关联的数据，不进行服务上线/下线的通知
            void DeleteDiscoverer(const BaseConnection::ptr &conn)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _conns.find(conn);
                if (it == _conns.end())
                    return;
                // 1. 从discoverers中删除discoverer
                for (auto &method : it->second->methods)
                {
                    auto discoverers = _discoverers[method];
                    discoverers.erase(it->second);
                }
                // 2. 从_conns中删除discoverer
                _conns.erase(it);
            }
            // 当有一个新的服务提供者上线，进行上线通知请求
            void OnlineNotify(const std::string &method, const Address &host)
            {
                return Notify(method, host, ServiceOptype::SERVICE_ONLINE);
            }
            // 当有一个服务提供者下线，进行下线通知请求
            void OfflineNotify(const std::string &method, const Address &host)
            {
                return Notify(method, host, ServiceOptype::SERVICE_OFFLINE);
            }

        private:
            void Notify(const std::string &method, const Address &host, ServiceOptype optype)
            {
                // 1. 新服务上线，需要通知发现过该服务的发现者
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _discoverers.find(method);
                if (it == _discoverers.end())
                    return;
                // 2. 但是需要提前包装好要发送的信息
                auto message = MessageFactory::CreateMessage<ServiceRequest>();
                message->SetId(UUID::GetUuid());
                message->SetMethod(method);
                message->SetMType(MType::REQ_SERVICE);
                message->SetOptype(optype);
                message->SetHost(host);
                for (auto &discoverer : it->second)
                {
                    discoverer->conn->Send(message);
                }
            }

        private:
            std::mutex _mutex;
            // 什么方法被哪些主机发现过
            std::unordered_map<std::string, std::set<Discoverer::ptr>> _discoverers;
            // 一个连接对应哪个服务发现者，发现过什么服务
            std::unordered_map<BaseConnection::ptr, Discoverer::ptr> _conns;
        };

        class ProviderDiscoverManager
        {
        public:
            using ptr = std::shared_ptr<ProviderDiscoverManager>;
            ProviderDiscoverManager()
                : _providers(std::make_shared<ProviderManager>()),
                  _discoverers(std::make_shared<DiscoverManager>()) {}
            // 接收服务操作请求(服务注册/服务发现)，并处理，进行响应
            void OnServiceRequest(const BaseConnection::ptr &conn, const ServiceRequest::ptr &message)
            {
                ServiceOptype optype = message->GetOptype();
                if (optype == ServiceOptype::SERVICE_REGISTRY)
                {
                    // 服务注册
                    LOGINFO("%s:%d 注册服务: %s", message->GetHost().first.c_str(), message->GetHost().second, message->GetMethod().c_str());
                    // 1. 新增服务提供者 -- 如果有，不会创建
                    _providers->AddProvider(conn, message->GetHost(), message->GetMethod());
                    // 2. 进行服务上线的通知
                    _discoverers->OnlineNotify(message->GetMethod(), message->GetHost());
                    // 3. 进行服务注册的响应
                    return RegisterResponse(conn, message);
                }
                else if (optype == ServiceOptype::SERVICE_DISCOVERY)
                {
                    // 服务发现
                    LOGINFO("%s:%d 注册发现: %s", message->GetHost().first.c_str(), message->GetHost().second, message->GetMethod().c_str());
                    // 1. 新增服务发现者 -- 如果有，不会创建
                    _discoverers->AddDiscoverer(conn, message->GetMethod());
                    // 2. 做出服务发现的响应
                    return DiscoveryResponse(conn, message);
                }
                else
                {
                    LOGERROR("收到了服务请求，但是服务请求类型错误");
                    // 做出异常的响应
                    ErrorResponse(conn, message);
                    return;
                }
            }
            // 连接关闭时的处理 -- 进行服务下线，以及服务下线的通知
            void OnConnShutDown(const BaseConnection::ptr &conn)
            {
                auto provider = _providers->GetProvider(conn);
                if (provider.get() != nullptr)
                {
                    LOGDEBUG("%s:%d 服务下线", provider->host.first.c_str(), provider->host.second);
                    for (auto &method : provider->methods)
                    {
                        // 1. 进行服务下线的通知
                        _discoverers->OfflineNotify(method, provider->host);
                    }
                    // 2. 删除服务提供者
                    _providers->DeleteProvider(conn);
                }
                // 3. 删除服务发现者
                _discoverers->DeleteDiscoverer(conn);
            }

        private:
            // 服务注册的响应
            void RegisterResponse(const BaseConnection::ptr &conn, const ServiceRequest::ptr &request)
            {
                // 组织响应信息，进行发送即可
                auto message = MessageFactory::CreateMessage<ServiceResponse>();
                message->SetId(request->GetRid());
                message->SetMType(MType::RSP_SERVICE);
                message->SetOptype(ServiceOptype::SERVICE_REGISTRY);
                message->SetRcode(RCode::RCODE_OK);
                conn->Send(message);
            }
            // 服务发现的响应
            void DiscoveryResponse(const BaseConnection::ptr &conn, const ServiceRequest::ptr &request)
            {
                // 组织响应信息，进行发送即可
                auto message = MessageFactory::CreateMessage<ServiceResponse>();
                message->SetId(request->GetRid());
                message->SetMType(MType::RSP_SERVICE);
                message->SetOptype(ServiceOptype::SERVICE_REGISTRY);
                // 服务发现，需要设置能够提供服务的服务端的信息
                std::vector<Address> hosts = _providers->GetMethodHosts(request->GetMethod());
                if (hosts.empty())
                {
                    message->SetRcode(RCode::RCODE_NOT_FOUND_SERVICE);
                    return conn->Send(message);
                }
                message->SetRcode(RCode::RCODE_OK);
                message->SetHost(hosts);
                message->SetMethod(request->GetMethod());
                return conn->Send(message);
            }
            // 服务操作异常的响应
            void ErrorResponse(const BaseConnection::ptr &conn, const ServiceRequest::ptr &request)
            {
                // 组织响应信息，进行发送即可
                auto message = MessageFactory::CreateMessage<ServiceResponse>();
                message->SetId(request->GetRid());
                message->SetMType(MType::RSP_SERVICE);
                message->SetOptype(ServiceOptype::SERVICE_UNKNOW);
                message->SetRcode(RCode::RCODE_INVALID_OPTYPE);
                conn->Send(message);
            }

        private:
            ProviderManager::ptr _providers;
            DiscoverManager::ptr _discoverers;
        };
    }
}